package com.crt.nexus.oauth.authorization;

import com.crt.nexus.oauth.service.ClientAuthorizationService;
import com.crt.nexus.oauth.service.UserAuthorizationService;
import com.crt.nexus.security.annotation.GrantType;
import com.crt.nexus.security.authentication.ClientDetail;
import com.crt.nexus.security.authentication.UserDetail;
import com.crt.nexus.security.domain.bean.ClientBean;
import com.google.common.collect.Maps;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.stream.Collectors;

import static com.crt.nexus.core.constant.SecurityConstants.GRANT_PASSWORD;
import static com.crt.nexus.security.jwt.JwtClaimsNames.AUTHORITIES;

@Slf4j
@Component
@GrantType(GRANT_PASSWORD)
@RequiredArgsConstructor
public class PasswordAuthenticationProvider implements AuthenticationProvider {

    private final UserAuthorizationService userAuthorizationService;
    private final ClientAuthorizationService clientAuthorizationService;

    @Override
    public Authentication authenticate(Authentication authentication) {
        String username = authentication.getName();
        ClientDetail client = clientAuthorizationService.getClientDetails((ClientBean) authentication.getDetails());
        UserDetail user = userAuthorizationService.getUserDetail(username);
        userAuthorizationService.authenticationChecks(user, (String) authentication.getCredentials());
        Map<String, Object> parameters = Maps.newHashMap();
        parameters.put(AUTHORITIES, user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()));
        return new OauthAuthenticationToken(user, user.getPassword(), client, parameters);
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return OauthAuthenticationToken.class.isAssignableFrom(authentication);
    }

}
